const koaBody = require('koa-bodyparser');
const wechatApi = require("wechat-api");
const session = require('koa-session');
const logger = require('koa-logger');
const helmet = require('koa-helmet');
const views = require('koa-views');
const mongo = require("./lib/mongo");
const path = require('path');
const _ = require('./api/route');
global.ObjectId = require('mongodb').ObjectID;
{//修改consolidate包中nunjucks渲染引擎的传递参数，已支持不autoescape渲染文本；
    const consolidate = require('consolidate');
    consolidate.nunjucks.render = function(str, options, cb) {
        function promisify(cb, fn) {
            return new Promise(function(resolve, reject) {
                cb = cb || function(err, html) {
                    if (err) {
                        return reject(err);
                    }
                    resolve(html);
                };
                fn(cb);
            });
        }
        return promisify(cb, function(cb) {
            try {
                let engine = require('nunjucks');
                let env = engine;
                // deprecated fallback support for express
                // <https://github.com/tj/consolidate.js/pull/152>
                // <https://github.com/tj/consolidate.js/pull/224>
                if (options.settings && options.settings.views) {
                    env = engine.configure(options.settings.views);
                } else if (options.nunjucks && options.nunjucks.configure) {
                    env = engine.configure.apply(engine, options.nunjucks.configure);
                }
                if (options.settings && typeof options.settings.autoescape === "boolean") {
                    engine.configure({autoescape:options.settings.autoescape});
                }

                //
                // because `renderString` does not initiate loaders
                // we must manually create a loader for it based off
                // either `options.settings.views` or `options.nunjucks` or `options.nunjucks.root`
                //
                // <https://github.com/mozilla/nunjucks/issues/730>
                // <https://github.com/crocodilejs/node-email-templates/issues/182>
                //

                // so instead we simply check if we passed a custom loader
                // otherwise we create a simple file based loader
                if (options.loader) {
                    env = new engine.Environment(options.loader);
                } else if (options.settings && options.settings.views) {
                    env = new engine.Environment(
                        new engine.FileSystemLoader(options.settings.views)
                    );
                } else if (options.nunjucks && options.nunjucks.loader) {
                    if (typeof options.nunjucks.loader === 'string') {
                        env = new engine.Environment(new engine.FileSystemLoader(options.nunjucks.loader));
                    } else {
                        env = new engine.Environment(
                            new engine.FileSystemLoader(
                                options.nunjucks.loader[0],
                                options.nunjucks.loader[1]
                            )
                        );
                    }
                }
                env.renderString(str, options, cb);
            } catch (err) {
                throw cb(err);
            }
        });
    };
}
module.exports = async (app, db) => {
    "use strict";
    let appSession = new mongo(db, "app.session");
    const CONFIG = {
        key: 'sid', /** (string) cookie key (default is koa:sess) */
        maxAge: 86400000, /** (number) maxAge in ms (default is 1 days) */
        overwrite: true, /** (boolean) can overwrite or not (default true) */
        httpOnly: true, /** (boolean) httpOnly or not (default true) */
        store: {
            get:async (key) => {
                let data = await appSession.findOne({_id:key});
                if(data){
                    data.session = JSON.parse(data.session);
                    data.session._expire = new Date(data.session.cookie.expires).getTime();
                    data.session._maxAge = data.session.cookie.originalMaxAge;
                    if(data.session.socketId) delete data.session.socketId;
                    delete data.session.cookie;
                    return data.session;
                } else {
                    return null;
                }
            }
            , set:async (key, sess, maxAge)=>{
                let sessionCookie = {cookie:{
                        originalMaxAge: maxAge
                        , expires: new Date(sess._expire)
                        , httpOnly: true
                        , path: "/"
                    }}, sessValue = Object.assign({}, sess);
                delete sessValue._expire;
                delete sessValue._maxAge;
                let keyValue =  Object.assign(sessionCookie, sessValue);
                await appSession.update({_id:key}, {$set:{session:JSON.stringify(keyValue), expires: new Date(sess._expire)}});
            }
            , destroy:async (key)=>{
                await appSession.remove({_id:key});
            }
        },
        signed: false /** (boolean) signed or not (default true) */
    };
    app.context.db = db;
    global.package = [
        {index:0, type:"day", name:"包日套餐", day:1, level:[{cost:1, limit:10000, level_id:0},{cost:2, limit:20000, level_id:1},{cost:4, limit:40000, level_id:2},{cost:8, limit:80000, level_id:3},{cost:12, limit:0, level_id:4}]},
        {index:1, type:"week", name:"包周套餐", day:7, level:[{cost:6, limit:10000, level_id:0},{cost:11, limit:20000, level_id:1},{cost:22, limit:40000, level_id:2},{cost:42, limit:80000, level_id:3},{cost:55, limit:0, level_id:4}]},
        {index:2, type:"month", name:"包月套餐", day:31, level:[{cost:26, limit:10000, level_id:0},{cost:50, limit:20000, level_id:1},{cost:94, limit:40000, level_id:2},{cost:178, limit:80000, level_id:3},{cost:234, limit:0, level_id:4}]},
        {index:3, type:"year", name:"包年套餐", day:365, level:[{cost:300, limit:10000, level_id:0},{cost:569, limit:20000, level_id:1},{cost:1075, limit:40000, level_id:2},{cost:2023, limit:80000, level_id:3},{cost:2656, limit:0, level_id:4}]}
    ];
    global.appName = "Spiker";
    app.use(session(CONFIG, app));
    app.use(koaBody({
        textLimit: '10mb',
        jsonLimit: '10mb'
    }));
    //app.use(logger());
    //app.use(helmet());
    //试图目录
    app.use(async (ctx, next) => {
        let content, viewPath;
        if (ctx.url.indexOf("/demo") >= 0) {
            viewPath = path.join(__dirname + '/../front/demo');
        } else if (ctx.url.indexOf("/vino") >= 0) {
            viewPath = path.join(__dirname + '/../front/backend');
        } else {
            viewPath = path.join(__dirname + '/../front/frontend');
        }
        content = await views(viewPath, {map: {html: 'nunjucks'}});
        await content(ctx, next);
    });
    const route = _();
    app.use(route.routes()).use(route.allowedMethods());

    //静态资源目录
    app.use(async (ctx, next) => {
        let content;
        let staticPath;
        if(ctx.url.indexOf("libs") >= 0 || ctx.url.indexOf("fonts") >= 0){
            staticPath = path.join(__dirname + '/../front/frontend');
        } else if(ctx.request.header.referer && ctx.request.header.referer.indexOf("/demo") >= 0){
            staticPath = path.join(__dirname + '/../front/demo');
        } else if (ctx.request.header.referer && ctx.request.header.referer.indexOf("/vino") >= 0) {
            staticPath = path.join(__dirname + '/../front/backend');
        } else {
            staticPath = path.join(__dirname + '/../front/frontend');
        }
        content = await require('koa-static')(staticPath, {});
        await content(ctx, next);
    });
    app.use(require('koa-static')(path.join(__dirname + '/../front'), {}));

    global.wxApi = new wechatApi("wx8e2d1f4622532d92", "c2c88e122b4795824f2079fd8bd1aa04"
        , async function (callback) {
            // 传入一个获取全局token的方法
            const appConfig = new mongo(mydb, 'app.config');
            let tokenInfo = await appConfig.findOne({key:"access_token"});
            if(!tokenInfo) return callback(null, null);
            callback(null, tokenInfo.value);
        }, async function (token, callback) {
            // 请将token存储到全局，跨进程、跨机器级别的全局，比如写到数据库、redis等
            // 这样才能在cluster模式及多机情况下使用，以下为写入到文件的示例
            const appConfig = new mongo(mydb, 'app.config');
            await appConfig.update({key:"access_token"}, {$set:{value:token}});
            callback(null);
        }
    );
    return app;

};